#include "BasicType/Color.h"

namespace GCRE {
	namespace BasicType {

		Color4b::Color4b( SFByte r, SFByte g, SFByte b, SFByte a ) : 
			R( r ), G( g ), B( b ), A( a )
		{

		}

		Color4b::Color4b( SFInt r, SFInt g, SFInt b, SFInt a )
		{
			if ( r > 255 ) r = 255; else if ( r < 0 ) r = 0;
			if ( g > 255 ) g = 255; else if ( g < 0 ) g = 0;
			if ( b > 255 ) b = 255; else if ( b < 0 ) b = 0;
			if ( a > 255 ) a = 255; else if ( a < 0 ) a = 0;

			R = (SFByte)r;
			G = (SFByte)g;
			B = (SFByte)b;
			A = (SFByte)a;
		}

		Color4b::Color4b( SFFloat r, SFFloat g, SFFloat b, SFFloat a )
		{
			if ( r > 255.0f ) r = 255.0f; else if ( r < 0.0f ) r = 0.0f;
			if ( g > 255.0f ) g = 255.0f; else if ( g < 0.0f ) g = 0.0f;
			if ( b > 255.0f ) b = 255.0f; else if ( b < 0.0f ) b = 0.0f;
			if ( a > 255.0f ) a = 255.0f; else if ( a < 0.0f ) a = 0.0f;

			R = (SFByte)r;
			G = (SFByte)g;
			B = (SFByte)b;
			A = (SFByte)a;
		}

		Color4b::Color4b( const Color4b& c ) :
			R( c.R ), G( c.G ), B( c.B ), A( c.A )
		{

		}

		Color4b::Color4b( const Color4f & c )
		{
			R = (SFByte)(255.0f * c.R );
			G = (SFByte)(255.0f * c.G );
			B = (SFByte)(255.0f * c.B );
			A = (SFByte)(255.0f * c.A );
		}

		Color4b::~Color4b()
		{

		}

		void Color4b::Set( SFInt r, SFInt g, SFInt b, SFInt a )
		{
			if ( r > 255 ) r = 255; else if ( r < 0 ) r = 0;
			if ( g > 255 ) g = 255; else if ( g < 0 ) g = 0;
			if ( b > 255 ) b = 255; else if ( b < 0 ) b = 0;
			if ( a > 255 ) a = 255; else if ( a < 0 ) a = 0;

			R = (SFByte)r;
			G = (SFByte)g;
			B = (SFByte)b;
			A = (SFByte)a;
		}

		void Color4b::Set( SFFloat r, SFFloat g, SFFloat b, SFFloat a )
		{
			if ( r > 255.0f ) r = 255.0f; else if ( r < 0.0f ) r = 0.0f;
			if ( g > 255.0f ) g = 255.0f; else if ( g < 0.0f ) g = 0.0f;
			if ( b > 255.0f ) b = 255.0f; else if ( b < 0.0f ) b = 0.0f;
			if ( a > 255.0f ) a = 255.0f; else if ( a < 0.0f ) a = 0.0f;

			R = (SFByte)r;
			G = (SFByte)g;
			B = (SFByte)b;
			A = (SFByte)a;
		}

		Color4b& Color4b::operator=( const Color4b& c )
		{
			R = c.R; G = c.G; B = c.B; A = c.A;
			return *this;
		}

		Color4b& Color4b::operator=( const Color4f& c )
		{
			R = (SFByte)(255.0f * c.R );
			G = (SFByte)(255.0f * c.G );
			B = (SFByte)(255.0f * c.B );
			A = (SFByte)(255.0f * c.A );
			return *this;
		}

		Color4b& Color4b::operator+=( const Color4b& c )
		{
			SFInt r = (SFInt)R + c.R;
			SFInt g = (SFInt)G + c.G;
			SFInt b = (SFInt)B + c.B;
			SFInt a = (SFInt)A + c.A;
			R = r > 255 ? 255 : (SFByte)r;
			G = g > 255 ? 255 : (SFByte)g;
			B = b > 255 ? 255 : (SFByte)b;
			A = a > 255 ? 255 : (SFByte)a;
			return *this;
		}

		Color4b& Color4b::operator+=( const Color4f& c )
		{
			SFFloat r = R + (255.0f * c.R );
			SFFloat g = G + (255.0f * c.G );
			SFFloat b = B + (255.0f * c.B );
			SFFloat a = A + (255.0f * c.A );
			R = r > 255.0f ? 255 : (SFByte)r;
			G = g > 255.0f ? 255 : (SFByte)g;
			B = b > 255.0f ? 255 :(SFByte) b;
			A = a > 255.0f ? 255 : (SFByte)a;
			return *this;
		}

		Color4b& Color4b::operator-=( const Color4b& c )
		{
			SFInt r = (SFInt)R - c.R;
			SFInt g = (SFInt)G - c.G;
			SFInt b = (SFInt)B - c.B;
			SFInt a = (SFInt)A - c.A;
			R = r < 0 ? 0 : (SFByte)r;
			G = g < 0 ? 0 : (SFByte)g;
			B = b < 0 ? 0 : (SFByte)b;
			A = a < 0 ? 0 : (SFByte)a;
			return *this;
		}

		Color4b& Color4b::operator-=( const Color4f& c )
		{
			SFFloat r = R - (255.0f * c.R );
			SFFloat g = G - (255.0f * c.G );
			SFFloat b = B - (255.0f * c.B );
			SFFloat a = A - (255.0f * c.A );
			R = r < 0.0f ? 0 : (SFByte)r;
			G = g < 0.0f ? 0 : (SFByte)g;
			B = b < 0.0f ? 0 :(SFByte) b;
			A = a < 0.0f ? 0 : (SFByte)a;
			return *this;
		}

		Color4b& Color4b::operator*=( SFFloat s )
		{
			assert( s >= 0.0f );
			SFFloat r = R * s;
			SFFloat g = G * s;
			SFFloat b = B * s;
			SFFloat a = A * s;
			R = r > 255.0f ? 255 : (SFByte)r;
			G = g > 255.0f ? 255 : (SFByte)g;
			B = b > 255.0f ? 255 :(SFByte) b;
			A = a > 255.0f ? 255 : (SFByte)a;
			return *this;
		}

		Color4b Color4b::operator+( const Color4b& c ) const
		{
			Color4b result( *this );
			result += c;
			return result;
		}

		Color4b Color4b::operator+( const Color4f& c ) const
		{
			Color4b result( *this );
			result += c;
			return result;
		}

		Color4b Color4b::operator-( const Color4b& c ) const
		{
			Color4b result( *this );
			result -= c;
			return result;
		}

		Color4b Color4b::operator-( const Color4f& c ) const
		{
			Color4b result( *this );
			result -= c;
			return result;
		}

		Color4b Color4b::operator*( SFFloat s ) const
		{
			Color4b result( *this );
			result *= s;
			return result;
		}

		Color4b operator*( SFFloat s, const Color4b& c )
		{
			return c * s;
		}

		Color4f::Color4f( SFFloat r, SFFloat g, SFFloat b, SFFloat a )
		{
			assert(	r >= 0.0f && r <= 1.0f && g >= 0.0f && g <= 1.0f && 
						b >= 0.0f && b <= 1.0f && a >= 0.0f && a <= 1.0f );
			R = r; G = g; B = b; A = a;
		}

		Color4f::Color4f( const Color4b& c )
		{
			R = c.R / 255.0f; G = c.G / 255.0f; B = c.B / 255.0f; A = c.A / 255.0f;
		}

		Color4f::Color4f( const Color4f& c )
		{
			R = c.R; G = c.G; B = c.B; A = c.A;
		}

		Color4f::Color4f( SFInt r, SFInt g, SFInt b, SFInt a )
		{
			if ( r > 255 ) r = 255; else if ( r < 0 ) r = 0;
			if ( g > 255 ) g = 255; else if ( g < 0 ) g = 0;
			if ( b > 255 ) b = 255; else if ( b < 0 ) b = 0;
			if ( a > 255 ) a = 255; else if ( a < 0 ) a = 0;
			R = r / 255.0f; G = g / 255.0f; B = b / 255.0f; A = a / 255.0f;
		}

		Color4f::~Color4f()
		{

		}

		void Color4f::Set( SFFloat r, SFFloat g, SFFloat b, SFFloat a )
		{
			assert(	r >= 0.0f && r <= 1.0f &&  g >= 0.0f && g <= 1.0f && 
						b >= 0.0f && b <= 1.0f &&  a >= 0.0f && a <= 1.0f );
			R = r; G = g; B = b; A = a;
		}

		void Color4f::Set( SFInt r, SFInt g, SFInt b, SFInt a )
		{
			if ( r > 255 ) r = 255; else if ( r < 0 ) r = 0;
			if ( g > 255 ) g = 255; else if ( g < 0 ) g = 0;
			if ( b > 255 ) b = 255; else if ( b < 0 ) b = 0;
			if ( a > 255 ) a = 255; else if ( a < 0 ) a = 0;
			R = r / 255.0f; G = g / 255.0f; B = b / 255.0f; A = a / 255.0f;
		}

		Color4f& Color4f::operator=( const Color4f& c )
		{
			R = c.R; G = c.G; B = c.B; A = c.A;
			return *this;
		}

		Color4f& Color4f::operator=( const Color4b& c )
		{
			R = c.R / 255.0f; G = c.G / 255.0f; B = c.B / 255.0f; A = c.A / 255.0f;
			return *this;
		}

		Color4f& Color4f::operator+=( const Color4f& c )
		{
			R += c.R; G += c.G; B += c.B; A += c.A;

			R = R > 1.0f ? 1.0f : R;
			G = G > 1.0f ? 1.0f : G;
			B = B > 1.0f ? 1.0f : B;
			A = A > 1.0f ? 1.0f : A;

			return *this;
		}

		Color4f& Color4f::operator+=( const Color4b& c )
		{
			R += c.R / 255.0f; G += c.G / 255.0f;
			B += c.B / 255.0f; A += c.A / 255.0f;

			R = R > 1.0f ? 1.0f : R;
			G = G > 1.0f ? 1.0f : G;
			B = B > 1.0f ? 1.0f : B;
			A = A > 1.0f ? 1.0f : A;

			return *this;
		}

		Color4f& Color4f::operator-=( const Color4f& c )
		{
			R -= c.R; G -= c.G; B -= c.B; A -= c.A;

			R = R < 0.0f ? 0.0f : R;
			G = G < 0.0f ? 0.0f : G;
			B = B < 0.0f ? 0.0f : B;
			A = A < 0.0f ? 0.0f : A;

			return *this;
		}

		Color4f& Color4f::operator-=( const Color4b& c )
		{
			R -= c.R / 255.0f; G -= c.G / 255.0f;
			B -= c.B / 255.0f; A -= c.A / 255.0f;

			R = R < 0.0f ? 0.0f : R;
			G = G < 0.0f ? 0.0f : G;
			B = B < 0.0f ? 0.0f : B;
			A = A < 0.0f ? 0.0f : A;

			return *this;
		}

		Color4f& Color4f::operator*=( SFFloat s )
		{
			assert( s > 0.0f );
			R *= s; G *= s; B *= s; A *= s;

			R = R > 1.0f ? 1.0f : R;
			G = G > 1.0f ? 1.0f : G;
			B = B > 1.0f ? 1.0f : B;
			A = A > 1.0f ? 1.0f : A;

			return *this;
		}

		Color4f Color4f::operator+( const Color4f& c ) const
		{
			Color4f result( *this );
			result += c;
			return result;
		}

		Color4f Color4f::operator+( const Color4b& c ) const
		{
			Color4f result( *this );
			result += c;
			return result;
		}

		Color4f Color4f::operator-( const Color4f& c ) const
		{
			Color4f result( *this );
			result -= c;
			return result;
		}

		Color4f Color4f::operator-( const Color4b& c ) const
		{
			Color4f result( *this );
			result -= c;
			return result;
		}

		Color4f Color4f::operator*( SFFloat s ) const
		{
			Color4f result( *this );
			result *= s;
			return result;
		}

		Color4f operator*( SFFloat s , const Color4f& c )
		{
			return c * s;
		}
	}
}